package com.xinz.srmi.impl;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import com.xinz.shared.exception.NetworkException;
import com.xinz.srmi.Buffer;
import com.xinz.srmi.ConfigFactory;
import com.xinz.srmi.InvokeConnector;
import com.xinz.srmi.NativeInterfaceProvider;
import com.xinz.srmi.NativeInvoker;
import com.xinz.srmi.RemoteInvoker;
import com.xinz.srmi.Session;
import com.xinz.srmi.SrmiClient;
import com.xinz.srmi.SrmiDefine;
/**
 * SRMI Socket连接客户端的简单实现
 * 初始化之后通过connect方法来连接服务端<br>
 * 一个SimpleSocketClient对象对应一个连接session。<br>
 * 目前方法调用是单通道的，这也意味着同一时刻只有一个方法被调用
 * 
 * @author xingyun
 *
 */
public class SimpleSocketClient extends SrmiClient{
	/***/
	DataOutputStream out;
	DataInputStream in;
	Socket socket;
	Object invokLock = new Object();
	Buffer invokResult;
	private static Executor deamoService = Executors.newSingleThreadExecutor();
	boolean isStartup = false;
	Object startupLock = new Object();
	
//	SocketChannel channel;
	public SimpleSocketClient(String host,int port, ConfigFactory foctyoy) throws IOException {
		super(foctyoy);
		this.socket = new Socket(host, port);
	}
	
	private Buffer readBuffer(DataInputStream in,int size) throws IOException{
		byte data[] = new byte[size];
		in.readFully(data);
		return new Buffer(data);
	}
	private void writeBuffer(DataOutputStream out,int type,Buffer buffer) throws IOException{
		out.writeShort(buffer.length+3);
		out.write(type);
		buffer.writeToStream(out);
		out.flush();
	}
	/***
	 * 连接到远程服务器
	 */
	public synchronized void connect() {
		super.connect();
		waitForStartUp();
	}
	private void waitForStartUp() {
		synchronized (startupLock) {
			try {
				startupLock.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}	
		}
	}
	int receive() throws SocketException{
		try{
			final int length = in.readShort();
			int type = in.read();
			//读取内容到buffer
			final Buffer receiveBuffer = readBuffer(in,length-3);
			//解析buffer类型
			if(type==SrmiDefine.TYPE_REQUEST_NORETURN){
				//避免server会掉递归
				deamoService.execute(new Runnable(){
					@Override
					public void run() {
						nativeInvoker.invoke(getSession(),receiveBuffer);
					}
				});
				
			}else if(type==SrmiDefine.TYPE_REQUEST){
				//这里先不做支持
				throw new IOException("不支持有返回的本地接口");
//				Buffer buffer = nativeInvoker.invoke(getSession(),receiveBuffer);
//				synchronized (out) {
//					writeBuffer(out, SrmiDefine.TYPE_RETURN,buffer);
//				}
			}else if(type==SrmiDefine.TYPE_RETURN){
				invokResult = receiveBuffer;
			}
			return type;
		}catch(SocketException e){
			throw e;
		}catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	
	@Override
	public void run() {
		try{
			out = new DataOutputStream(socket.getOutputStream()); 
			in = new DataInputStream(socket.getInputStream());
			isStartup = true;
			synchronized (startupLock) {
				startupLock.notifyAll();
			}
			while(true){
				int type = receive();
				if(type==SrmiDefine.TYPE_RETURN){
					synchronized(invokLock){
						invokLock.notifyAll();
					}
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public  Buffer request(Buffer request) throws IOException {	
		synchronized(invokLock){//一次只允许一个请求存在
			//判断是否是递归调用，FIXME:递归的时候或许有逻辑问题? zzz...
			if(Thread.currentThread()==this){
				writeBuffer(out,SrmiDefine.TYPE_REQUEST,request);
				while(receive()!=SrmiDefine.TYPE_RETURN);
			}else{
				synchronized (out) {
					writeBuffer(out,SrmiDefine.TYPE_REQUEST,request);
				}
				try { invokLock.wait(); } catch (InterruptedException e) { e.printStackTrace();}
			}
		}
		return invokResult;
	}
}
